
#include "..\d3d.h"

#include "d3d_watershader.h"
#include "..\..\common\def.h"
#include "..\..\engine\engine.h"
#include "d3d_lightshader.h"


/**************************************
 *
 **************************************/
D3DWaterShader::D3DWaterShader(CD3D9Device *pDevice) : D3DShader(pDevice)
{
	mp_CameraPositionHandle = NULL; 
}

/**************************************
 *
 **************************************/
D3DWaterShader::~D3DWaterShader()
{
	Release();
}

/**************************************
 *
 **************************************/
string D3DWaterShader::GetType() const
{
	return string("D3DWaterShader"); 
}

/**************************************
 *
 **************************************/
unsigned int D3DWaterShader::RenderOrder()
{
	return 1;
}

/**************************************
 * Appreciates that shaders can be executed
 * many times perframe. This provides opporutnity
 * to preform one-off initilization on a per-frame
 * basis
 **************************************/
void D3DWaterShader::PreExecute()
{
	if(FAILED(UpdateParameters(m_pEffect)))
		return;
}
/**************************************
 * Implementations to aquire specfiy custom 
 * effect parameters
 **************************************/
HRESULT D3DWaterShader::InitalizeParameters(LPD3DXEFFECT pEffect)
{
	HRESULT hr;
	do {

		if(ISNULL(pEffect)) {
			EE_LOGERROR("Invalid parameter.");
			hr = E_INVALIDARG;
			break;
		}

		m_pProjectionHandle = pEffect->GetParameterBySemantic( NULL, "PROJECTION" ); 
		m_pViewHandle = pEffect->GetParameterBySemantic( NULL, "VIEW" ); 		
		m_pTimeHandle = pEffect->GetParameterBySemantic( NULL, "TIME" ); 
		m_pFogHandle = pEffect->GetParameterBySemantic( NULL, "FOG_DATA" ); 
		mp_CameraPositionHandle = pEffect->GetParameterBySemantic( NULL, "CAMERAWS" ); 
		
		if(ISNULL(m_pProjectionHandle) || ISNULL(m_pViewHandle) || ISNULL(m_pFogHandle)
			|| ISNULL(m_pTimeHandle) || ISNULL(mp_CameraPositionHandle)) {
			EE_LOGERROR("Unknown semantic.");
			hr = E_UNEXPECTED;
			break;
		}
		return S_OK;
	
	}while(false);
	
	mp_CameraPositionHandle = NULL;
	m_pProjectionHandle = NULL;
	m_pViewHandle = NULL;
	m_pTimeHandle = NULL;
	m_pFogHandle = NULL;
	return hr;
}

/**************************************
 * Implementations to update custom 
 * effect parameters
 **************************************/
HRESULT D3DWaterShader::UpdateParameters(LPD3DXEFFECT pEffect)
{
	if(ISNULL(pEffect))
		return E_FAIL;

	CEngine* const pEngineInstance = CEngine::GetInstance();
	const ViewOrrientation* pCamera = &GetDevice()->m_camera; 

	pEffect->SetMatrix(m_pProjectionHandle,&pCamera->m_Projection); 
	pEffect->SetMatrix(m_pViewHandle,&pCamera->m_View); 
	pEffect->SetFloat(m_pTimeHandle,pEngineInstance->GetTimeDuration()); 
	pEffect->SetVector(mp_CameraPositionHandle, &VectorToD3DVector4(pEngineInstance->GetCamera()->getPosition())); 
	
	return S_OK;
}

/**************************************
 * Executes the shader which usually results
 * in geometry being Drawn
 **************************************/
void D3DWaterShader::Execute(const int flags)
{
	if(!(flags & (~RENDER_LIGHTING & RENDER_TRANSPARENT)))
		return; 

	unsigned int passes = 0;

	LPDIRECT3DDEVICE9 pDevice = GetDevice()->m_pD3DDevice; 
	
	if(FAILED(ConstructInstanceBuffer()))
		return;

	unsigned int instanceBytesOffset = 0; 
	unsigned int vertexOffset = 0;
	pDevice->SetStreamSource(0, m_pMeshVB, 0, VertexComplex::size); 

	for(unsigned int i = 0;  i < m_MeshCount;  i++)
	{
		HashTable<InstanceData, D3DRenderable*>::Pair *pPair = m_MeshHashInstances.GetPair(i); 
		D3DRenderable* pMesh = pPair->m_Key;
		
	#ifdef _DEBUG
	{
		LPCWSTR pMsg = L"Begin render water\n"; 
		D3DPERF_SetMarker(D3DCOLOR_COLORVALUE(1,0,0,1), pMsg); 
	}
	#endif
		SetTextures(pMesh);

	GetDevice()->SetTexture(3, GetDevice()->m_pLightShader->m_RTDepth->m_pTargetTexture); 
	GetDevice()->SetTexture(4, GetDevice()->m_pRTRefractionBuffer->m_pTargetTexture); 

		pDevice->SetStreamSourceFreq(0, D3DSTREAMSOURCE_INDEXEDDATA | pPair->m_Count); 
		
		pDevice->SetStreamSource(1, m_pInstanceVB, instanceBytesOffset, m_vbInstanceSize); 
		pDevice->SetStreamSourceFreq(1, D3DSTREAMSOURCE_INSTANCEDATA | 1); 
		pDevice->SetIndices(pMesh->pIndexBuffer); 

		m_pEffect->Begin(&passes, 0); 
		for(unsigned int p = 0;  p < passes;  p++)
		{
			m_pEffect->BeginPass(p); 
			pMesh->Render(vertexOffset);
			m_pEffect->EndPass(); 
		}
		m_pEffect->End(); 
		instanceBytesOffset += (pPair->m_Count * m_vbInstanceSize); 
		vertexOffset += pMesh->getVertexCount();
	#ifdef _DEBUG
	{
		LPCWSTR pMsg = L"End render water\n"; 
		D3DPERF_SetMarker(D3DCOLOR_COLORVALUE(1,0,0,1), pMsg); 
	}
	#endif
	}

	pDevice->SetStreamSourceFreq(0, 1); 
	pDevice->SetStreamSourceFreq(1, 1); 
}
